package com.qing.simple_player.viewmodel;

import static com.qing.simple_player.player.IPlayer.playStateToString;

import android.content.Context;
import android.content.Intent;

import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.media3.common.MediaItem;

import com.qing.simple_player.player.BasePlayerImpl;
import com.qing.simple_player.player.IPlayer;
import com.qing.simple_player.util.AssertUtil;
import com.qing.simple_player.util.DebugLog;

import java.util.Objects;

/**
 * 双路播放器，同时播放两个音频，播放器实现为ExoPlayer
 */
public class DoublePlayerViewModel extends SinglePlayerViewModel {

    private final MutableLiveData<Integer> mPlayState = new MutableLiveData<>(PLAY_STATE_IDLE);

    private final MutableLiveData<Integer> mPlayStateCombined = new MediatorLiveData<>() {
        @PlaySate
        private Integer mLastPlayState1 = null;
        @PlaySate
        private Integer mLastPlayState2 = null;

        {
            // 添加数据源，当数据源中的数据发生改变时，更新mPlayStateCombined的值，其中会进行observer，因此需要在主线程初始化
            runOnMainThread(() -> {
                addSource(DoublePlayerViewModel.super.getPlaybackState(), playState -> {
                    mLastPlayState1 = playState;
                    setValue(combinePlayState(mLastPlayState1, mLastPlayState2));
                });
                addSource(mPlayState, playState -> {
                    mLastPlayState2 = playState;
                    setValue(combinePlayState(mLastPlayState1, mLastPlayState2));
                });
            });
        }
    };

    private final MutableLiveData<Long> mPlayProgress = new MutableLiveData<>(0L);

    private final MutableLiveData<Long> mPlayProgressCombined = new MediatorLiveData<>() {
        private Long mLastProgress1 = null;
        private Long mLastProgress2 = null;

        {
            // 添加数据源，当数据源中的数据发生改变时，更新mPlayProgressCombined的值，其中会进行observer，因此需要在主线程初始化
            runOnMainThread(() -> {
                addSource(DoublePlayerViewModel.super.getPlayProgress(), progress -> {
                    mLastProgress1 = progress;
                    setValue(combinePlayProgress(mLastProgress1, mLastProgress2));
                });
                addSource(mPlayProgress, progress -> {
                    mLastProgress2 = progress;
                    setValue(combinePlayProgress(mLastProgress1, mLastProgress2));
                });
            });
        }
    };

    private final MutableLiveData<Long> mPlayDuration = new MutableLiveData<>(0L);

    private final MutableLiveData<Long> mPlayDurationCombined = new MediatorLiveData<>() {
        private Long mLastDuration1 = null;
        private Long mLastDuration2 = null;

        {
            // 添加数据源，当数据源中的数据发生改变时，更新mPlayDurationCombined的值，其中会进行observer，因此需要在主线程初始化
            runOnMainThread(() -> {
                addSource(DoublePlayerViewModel.super.getPlayDuration(), duration -> {
                    mLastDuration1 = duration;
                    setValue(combinePlayDuration(mLastDuration1, mLastDuration2));
                });
                addSource(mPlayDuration, duration -> {
                    mLastDuration2 = duration;
                    setValue(combinePlayDuration(mLastDuration1, mLastDuration2));
                });
            });
        }
    };

    private int mPendingPlaybackState = PLAY_STATE_IDLE;
    private long mPendingPlayProgress = 0L;
    private long mPendingPlayDuration = 0L;

    private final IPlayer mPlayerImpl;

    private final Listener mPlayStatsListener = new Listener() {
        @Override
        public void onProgressChanged(long positionMs, long durationMs) {
            setPlayProgress(positionMs);
            setPlayDuration(durationMs);
        }

        @Override
        public void onPlayStateChanged(int state) {
            setPlaybackState(state);
        }
    };

    public DoublePlayerViewModel(Context context, String tag, Intent sessionIntent) {
        this(context, true, tag, sessionIntent);
    }

    public DoublePlayerViewModel(Context context, boolean bindSession, String tag, Intent sessionIntent) {
        super(context, bindSession, tag, sessionIntent);
        mPlayerImpl = new BasePlayerImpl(context, false, mPlayStatsListener, tag + "_2", sessionIntent);
    }

    @Override
    protected String initChildTag() {
        return "DoublePlayerViewModel";
    }

    @Override
    public final LiveData<Integer> getPlaybackState() {
        return mPlayStateCombined;
    }

    private void setPlaybackState(@PlaySate int state) {
        if (mPendingPlaybackState != state) {
            mPendingPlaybackState = state;
            // postValue会导致状态丢失
            runOnMainThread(() -> mPlayState.setValue(state));
        }
    }

    @Override
    public final LiveData<Long> getPlayProgress() {
        return mPlayProgressCombined;
    }

    private void setPlayProgress(long positionMs) {
        if (DEBUG) {
            DebugLog.d(CHILD_TAG, "DoublePlayerViewModel#setPlayDuration: positionMs=" + positionMs + ", mPendingPosition=" + mPendingPlayProgress);
        }
        if (mPendingPlayProgress != positionMs) {
            mPendingPlayProgress = positionMs;
            if (isMainThread()) {
                mPlayProgress.setValue(positionMs);
            } else {
                mPlayProgress.postValue(positionMs);
            }
        }
    }

    @Override
    public LiveData<Long> getPlayDuration() {
        return mPlayDurationCombined;
    }

    private void setPlayDuration(long durationMs) {
        if (DEBUG) {
            DebugLog.d(CHILD_TAG, "setPlayDuration: durationMs=" + durationMs + ", mPendingDuration=" + mPendingPlayDuration);
        }
        if (mPendingPlayDuration != durationMs) {
            mPendingPlayDuration = durationMs;
            if (isMainThread()) {
                mPlayDuration.setValue(durationMs);
            } else {
                mPlayDuration.postValue(durationMs);
            }
        }
    }

    public void setMediaItems(@NonNull MediaItem... mediaItems) {
        AssertUtil.checkArgument(mediaItems.length == 2, "mediaItems.length must be 2");
        super.setMediaItems(mediaItems[0]);
        mPlayerImpl.setMediaItems(mediaItems[1]);
    }

    @Override
    public void play() {
        super.play();
        mPlayerImpl.play();
    }

    @Override
    public void pause() {
        super.pause();
        mPlayerImpl.pause();
    }

    @Override
    public void stop() {
        super.stop();
        mPlayerImpl.stop();
    }

    @Override
    public void seekTo(long positionMs) {
        super.seekTo(positionMs);
        mPlayerImpl.seekTo(positionMs);
    }

    @Override
    public void setPlayWhenReady(boolean playWhenReady) {
        super.setPlayWhenReady(playWhenReady);
        mPlayerImpl.setPlayWhenReady(playWhenReady);
    }

    @Override
    public long getCurrentPosition() {
        return getPlayProgress().getValue() == null ? super.getCurrentPosition() : getPlayProgress().getValue();
    }

    @Override
    public void release() {
        super.release();
        mPlayerImpl.release();
    }

    @Override
    public void setPlaybackSpeed(float speed) {
        super.setPlaybackSpeed(speed);
        mPlayerImpl.setPlaybackSpeed(speed);
    }

    /**
     * 合并播放状态，当前播放状态与播放器状态合并，相同时直接返回，不同时进行合并
     * 当前仅处理PLAY_STATE_BUFFERING和PLAY_STATE_READY，以及PLAY_STATE_PLAYING和PLAY_STATE_ENDED的状态，其他以最大值为准（对齐长音频）
     *
     * @param state1 状态一
     * @param state2 状态二
     * @return 合并后的播放状态
     */
    @PlaySate
    private static Integer combinePlayState(@PlaySate Integer state1, @PlaySate Integer state2) {
        DebugLog.d(TAG, "combinePlayState: 合并状态 state1=" + (state1 != null ? playStateToString(state1) : "null") + ", state2=" + (state2 != null ? playStateToString(state2) : "null"));
        if (Objects.equals(state1, state2)) return state1;
        if (state1 == null || state2 == null) {
            if (state1 == null) return state2;
            return state1;
        } else {
            // 播放状态合并，播放时需保证为READY，结束时为ENDED
            if (state1 == PLAY_STATE_READY || state2 == PLAY_STATE_READY) {
                return PLAY_STATE_BUFFERING;
            }
            if ((state1 == PLAY_STATE_ENDED && state2 == PLAY_STATE_PLAYING) || (state1 == PLAY_STATE_PLAYING && state2 == PLAY_STATE_ENDED)) {
                return PLAY_STATE_PLAYING;
            }
            return Math.max(state1, state2);
        }
    }

    /**
     * 合并播放进度，取最大值
     *
     * @param progress1 进度一
     * @param progress2 进度二
     * @return 合并后的播放进度
     */
    @NonNull
    private static Long combinePlayProgress(Long progress1, Long progress2) {
        if (DEBUG) {
            DebugLog.d(TAG, "combinePlayProgress: progress1=" + progress1 + ", progress2=" + progress2);
        }
        if (progress1 == null) return progress2 != null ? progress2 : 0L;
        if (progress2 == null) return progress1;
        return Math.max(progress1, progress2);
    }

    /**
     * 合并播放时长，取最大值
     *
     * @param duration1 时长一
     * @param duration2 时长二
     * @return 合并后的播放时长
     */
    @NonNull
    private static Long combinePlayDuration(Long duration1, Long duration2) {
        if (DEBUG) {
            DebugLog.d(TAG, "combinePlayProgress: duration1=" + duration1 + ", duration2=" + duration2);
        }
        if (duration1 == null) return duration2 != null ? duration2 : 0L;
        if (duration2 == null) return duration1;
        return Math.max(duration1, duration2);
    }
}
